---
title: Services
---
import Tabs from '@theme/Tabs';
import TabItem from '@theme/TabItem';

`@nestjs-query` provides a common interface to use difference ORMs inorder to query and mutate your data.

The following ORMs are supported out of the box.

* [TypeOrm](./typeorm/getting-started.md)
* [Sequelize](./sequelize/getting-started.md)
* [Mongoose](./mongoose/getting-started.md)
* [Typegoose](./typegoose/getting-started.md)

`@nestjs-query/core` also provides a number of base `QueryService`s that can be used to create custom query services.
 [See the Services docs](../concepts/services.md#service-helpers)

All examples assume the following entity.

<Tabs
  defaultValue="typeorm"
  groupId="orm"
  values={[
    { label: 'TypeOrm', value: 'typeorm', },
    { label: 'Sequelize', value: 'sequelize', },
    { label: 'Mongoose', value: 'mongoose', },
    { label: 'Typegoose', value: 'typegoose', },
  ]
}>
<TabItem value="typeorm">

```ts title="todo-item.entity.ts"
import { Column, CreateDateColumn, Entity, PrimaryGeneratedColumn, UpdateDateColumn } from 'typeorm';

@Entity()
export class TodoItemEntity {
  @PrimaryGeneratedColumn()
  id!: string;

  @Column()
  title!: string;

  @Column()
  completed!: boolean;

  @CreateDateColumn()
  created!: Date;

  @UpdateDateColumn()
  updated!: Date;
}
```

</TabItem>
<TabItem value="sequelize">

```ts title="todo-item.entity.ts"
import {
  Table,
  Column,
  Model,
  AllowNull,
  CreatedAt,
  UpdatedAt,
  PrimaryKey,
  AutoIncrement,
} from 'sequelize-typescript';

@Table
export class TodoItemEntity extends Model<TodoItemEntity, Partial<TodoItemEntity>> {
  @PrimaryKey
  @AutoIncrement
  @Column
  id!: number;

  @Column
  title!: string;

  @AllowNull
  @Column
  description?: string;

  @Column
  completed!: boolean;

  @CreatedAt
  created!: Date;

  @UpdatedAt
  updated!: Date;
}
```

</TabItem>
<TabItem value="mongoose">

```ts title="todo-item.entity.ts"
import { Prop, Schema, SchemaFactory } from '@nestjs/mongoose';
import { Document } from 'mongoose';

@Schema({ timestamps: { createdAt: 'created', updatedAt: 'updated' } })
export class TodoItemEntity extends Document {
  @Prop({ required: true })
  title!: string;

  @Prop()
  description?: string;

  @Prop({ required: true })
  completed!: boolean;

  @Prop({ default: Date.now })
  created!: Date;

  @Prop({ default: Date.now })
  updated!: Date;
}

export const TodoItemEntitySchema = SchemaFactory.createForClass(TodoItemEntity);
```

</TabItem>
<TabItem value="typegoose">

```ts title="todo-item.entity.ts"
import { Base } from '@typegoose/typegoose/lib/defaultClasses';
import { Prop, modelOptions, Ref } from '@typegoose/typegoose';
import { Types } from 'mongoose';
import { SubTaskEntity } from '../sub-task/sub-task.entity';
import { TagEntity } from '../tag/tag.entity';

@modelOptions({
  schemaOptions: {
    timestamps: { createdAt: 'created', updatedAt: 'updated' },
    collection: 'todo-items',
    toObject: { virtuals: true },
  },
})
export class TodoItemEntity implements Base {
  @Prop({ required: true })
  title!: string;

  @Prop()
  description?: string;

  @Prop({ required: true })
  completed!: boolean;

  @Prop({ default: Date.now })
  created!: Date;

  @Prop({ default: Date.now })
  updated!: Date;
}

```

</TabItem>
</Tabs>


## Creating a Service

### Module

The `nestjs-query` `typeorm`, `sequelize`, `mongoose`, and 'typegoose' packages provide a module that will add providers
 to inject auto-created `QueryServices` using the `@InjectQueryService` decorator.

In order to use the decorator you will need to use the module that comes with the `nestjs-query` orm module providing it your entities that you want the services created for.

<Tabs
  defaultValue="typeorm"
  groupId="orm"
  values={[
    { label: 'TypeOrm', value: 'typeorm', },
    { label: 'Sequelize', value: 'sequelize', },
    { label: 'Mongoose', value: 'mongoose', },
    { label: 'Typegoose', value: 'typegoose', },
  ]
}>
<TabItem value="typeorm">

```ts title="todo-item.module.ts" {8}
import { NestjsQueryTypeOrmModule } from '@nestjs-query/query-typeorm';
import { Module } from '@nestjs/common';
import { TodoItemEntity } from './todo-item.entity';
import { TodoItemResolver } from './todo-item.resolver';

@Module({
  providers: [TodoItemResolver],
  imports: [NestjsQueryTypeOrmModule.forFeature([TodoItemEntity])],
})
export class TodoItemModule {}

```

</TabItem>
<TabItem value="sequelize">

```ts title="todo-item.module.ts" {8}
import { NestjsQuerySequelizeModule } from '@nestjs-query/query-sequelize';
import { Module } from '@nestjs/common';
import { TodoItemEntity } from './todo-item.entity';
import { TodoItemResolver } from './todo-item.resolver';

@Module({
  providers: [TodoItemResolver],
  imports: [NestjsQuerySequelizeModule.forFeature([TodoItemEntity])],
})
export class TodoItemModule {}
```

</TabItem>
<TabItem value="mongoose">

```ts title="todo-item.module.ts" {9-11}
import { NestjsQueryMongooseModule } from '@nestjs-query/query-mongoose';
import { Module } from '@nestjs/common';
import { TodoItemEntity } from './todo-item.entity';
import { TodoItemResolver } from './todo-item.resolver';

@Module({
  providers: [TodoItemResolver],
  imports: [
    NestjsQueryMongooseModule.forFeature([
      { document: TodoItemEntity, name: TodoItemEntity.name, schema: TodoItemEntitySchema },
    ]),
  ],
})
export class TodoItemModule {}
```

</TabItem>
<TabItem value="typegoose">

```ts title="todo-item.module.ts" {8}
import { NestjsQueryTypegooseModule } from '@nestjs-query/query-typegoose';
import { Module } from '@nestjs/common';
import { TodoItemEntity } from './todo-item.entity';
import { TodoItemResolver } from './todo-item.resolver';

@Module({
  providers: [TodoItemResolver],
  imports: [NestjsQueryTypegooseModule.forFeature([TodoItemEntity])],
})
export class TodoItemModule {}
```

</TabItem>
</Tabs>

### Decorator

Once you have imported the correct module, use `@InjectQueryService` decorator to inject a `QueryService` into your class or resolver.

```ts title="todo-item.resolver.ts" {10}
import { QueryService, InjectQueryService } from '@nestjs-query/core';
import { CRUDResolver } from '@nestjs-query/query-graphql';
import { Resolver } from '@nestjs/graphql';
import { TodoItemDTO } from './todo-item.dto';
import { TodoItemEntity } from './todo-item.entity';

@Resolver(() => TodoItemDTO)
export class TodoItemResolver extends CRUDResolver(TodoItemDTO) {
  constructor(
    @InjectQueryService(TodoItemEntity) readonly service: QueryService<TodoItemEntity>
  ) {
    super(service);
  }
}
```

:::note
The above resolver is an example of manually defining the resolver, if you use the `NestjsQueryGraphQLModule` you do not need to define a resolver.
:::

:::note
In the above example the DTO and entity are the same shape, if you have a case where they are different or have
computed fields check out [Assemblers](../concepts/advanced/assemblers.mdx) to understand how to convert to and from
the
DTO/Entity.
:::

## Querying

The `nestjs-query` QueryService uses a common `Query` interface that allows you use a common type regardless of the persistence library in use.

 To query for records from your service you can use the `query` method which will return a `Promise` of an array of
 entities. To read more about querying take a look at the [Queries Doc](../concepts/queries.mdx).

#### Example

Get all records

```ts
const records = await this.service.query({});
```

### Filtering

The `filter` option is translated to a `WHERE` clause.

#### Example

To find all completed `TodoItems` by use can use the `is` operator.

```ts
const records = await this.service.query({
   filter : {
     completed: { is: true },
   },
});
```

### Sorting

The `sorting` option is translated to a `ORDER BY`.

#### Example

Sorting records by `completed` and `title`.

```ts
const records = await this.service.query({
  sorting: [
    {field: 'completed', direction: SortDirection.ASC},
    {field: 'title', direction: SortDirection.DESC},
  ],
});
```

### Paging

The `paging` option is translated to `LIMIT` and `OFFSET`.

#### Example

Skip the first 20 records and return the next 10.

```ts
const records = await this.service.query({
  paging: {limit: 10, offset: 20},
});
```

### Find By Id

To find a single record you can use the `findById` method.

#### Example

```ts
const records = await this.service.findById(1);
```

### Get By Id

The `getById` method is the same as the `findById` with one key difference, it will throw an exception if the record is not found.

#### Example

```ts
try {
  const records = await this.service.getById(1);
} catch (e) {
  console.error('Unable to get record with id = 1');
}
```

### Aggregating

To perform an `aggregate` query you can use the `aggregate` method which accepts a `Filter` and `AggregateQuery`.

Supported aggregates are `count`, 'sum', 'avg', `min` and `max`.

In this example we'll aggregate on all records.

```ts
const aggregateResponse = await this.service.aggregate({}, {
    count: ['id'],
    min: ['title'],
    max: ['title']
});
```

The response will look like the following

```ts
[
  {
    count: {
      id: 10
    },
    min: {
      title: 'Aggregate Todo Items'
    },
    min: {
      title: 'Query Todo Items'
    },
  }
]
```

In this example we'll aggregate on all completed TodoItems

```ts
const aggregateResponse = await this.service.aggregate({ completed: { is: true } }, {
    count: ['id'],
    min: ['title'],
    max: ['title']
});
```

## Creating

### Create One

To create a single record use the `createOne` method.

#### Example

```ts
const createdRecord = await this.service.createOne({
  title: 'Foo',
  completed: false,
});
```

### Create Many

To create multiple records use the `createMany` method.

#### Example

```ts
const createdRecords = await this.service.createMany([
  { title: 'Foo', completed: false },
  { title: 'Bar', completed: true },
]);
```

## Updating

### Update One

To update a single record use the `updateOne` method.

#### Example

Updates the record with an id equal to 1 to completed.

```ts
const updatedRecord = await this.service.updateOne(1, { completed: true });
```

### Update Many

To update multiple records use the `updateMany` method.

**NOTE** This method returns a `UpdateManyResponse` which contains the updated record count.

#### Example

Updates all `TodoItemEntities` to completed if their title ends in `Bar`

```ts
const { updatedCount } = await this.service.updateMany(
  {completed: true}, // update
  {completed: {is: false}, title: {like: '%Bar'}} // filter
);
```

## Deleting

### Delete One

To delete a single record use the `deleteOne` method.

#### Example

Delete the record with an id equal to 1.

```ts
const deletedRecord = await this.service.deleteOne(1);
```

### Delete Many

To delete multiple records use the `deleteMany` method.

**NOTE** This method returns a `DeleteManyResponse` which contains the deleted record count.

#### Example

Delete all `TodoItemEntities` older than `Jan 1, 2019`.

```ts
const { deletedCount } = await this.service.deleteMany(
  { created: { lte: new Date('2019-1-1') } } // filter
);
```

## Foreign Keys

It is a common use case to include a foreign key from your entity in your DTO.

To do this you should add the foreign key to your entity as well as your DTO.

:::note
This section only applies when using typeorm and sequelize with relations
:::

### Example

Assume TodoItems can have SubTasks we would set up our SubTaskEntity using the following

<Tabs
  defaultValue="typeorm"
  groupId="orm"
  values={[
    { label: 'TypeOrm', value: 'typeorm', },
    { label: 'Sequelize', value: 'sequelize', },
  ]
}>
<TabItem value="typeorm">

```ts title="sub-task.entity.ts"
import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  ObjectType,
  ManyToOne,
  JoinColumn,
} from 'typeorm';
import { TodoItemEntity } from '../todo-item/todo-item.entity';

@Entity({ name: 'sub_task' })
export class SubTaskEntity {
  @PrimaryGeneratedColumn()
  id!: number;

  @Column()
  title!: string;

  @Column({ nullable: true })
  description?: string;

  @Column()
  completed!: boolean;

  // add the todoItemId to the model
  @Column({ nullable: false, name: 'todo_item_id' })
  todoItemId!: string;

  @ManyToOne((): ObjectType<TodoItemEntity> => TodoItemEntity, (td) => td.subTasks, {
    onDelete: 'CASCADE',
    nullable: false,
  })
  // specify the join column we want to use.
  @JoinColumn({ name: 'todo_item_id' })
  todoItem!: TodoItemEntity;

  @CreateDateColumn()
  created!: Date;

  @UpdateDateColumn()
  updated!: Date;
}
```

</TabItem>
<TabItem value="sequelize">

```ts title="sub-task.entity.ts"
import {
  Table,
  AllowNull,
  Column,
  ForeignKey,
  BelongsTo,
  CreatedAt,
  UpdatedAt,
  Model,
  AutoIncrement,
  PrimaryKey,
} from 'sequelize-typescript';
import { TodoItemEntity } from '../todo-item/entity/todo-item.entity';

@Table({})
export class SubTaskEntity extends Model<SubTaskEntity, Partial<SubTaskEntity>> {
  @PrimaryKey
  @AutoIncrement
  @Column
  id!: number;

  @Column
  title!: string;

  @AllowNull
  @Column
  description?: string;

  @Column
  completed!: boolean;

  @Column
  @ForeignKey(() => TodoItemEntity)
  todoItemId!: number;

  @BelongsTo(() => TodoItemEntity)
  todoItem!: TodoItemEntity;

  @CreatedAt
  created!: Date;

  @UpdatedAt
  updated!: Date;
}
```

</TabItem>
</Tabs>


Then we could add the `todoItemId` to the SubTaskDTO.

```ts title="sub-task.dto.ts" {24-26}
import { FilterableField, IDField } from '@nestjs-query/query-graphql';
import { ObjectType, ID, GraphQLISODateTime } from '@nestjs/graphql';

@ObjectType('SubTask')
export class SubTaskDTO {
  @IDField(() => ID)
  id!: number;

  @FilterableField()
  title!: string;

  @FilterableField({ nullable: true })
  description?: string;

  @FilterableField()
  completed!: boolean;

  @FilterableField(() => GraphQLISODateTime)
  created!: Date;

  @FilterableField(() => GraphQLISODateTime)
  updated!: Date;

  // expose the todoItemId as a filterable field.
  @FilterableField()
  todoItemId!: string;
}
```

## Relations

:::note
This section only applies when you combine your DTO and entity and are using Typeorm or Sequelize
:::

When your DTO and entity are the same class and you have relations defined, you should not decorate your the relations in the DTO with `@Field` or `@FilterableField`.

Instead decorate the class with `@CursorConnection`, `@OffsetConnection`, '@UnPagedRelation' or `@Relation`.

### Example

Assume you have the following subtask definition.
<Tabs
  defaultValue="typeorm"
  groupId="orm"
  values={[
    { label: 'TypeOrm', value: 'typeorm', },
    { label: 'Sequelize', value: 'sequelize', },
  ]
}>
<TabItem value="typeorm">

```ts title="sub-task.ts"  {15,38-44}
import {
  Entity,
  PrimaryGeneratedColumn,
  Column,
  CreateDateColumn,
  UpdateDateColumn,
  ManyToOne,
  JoinColumn,
} from 'typeorm';
import { ObjectType, ID } from '@nestjs/graphql';
import { FilterableField, IDField, Relation } from '@nestjs-query/query-graphql';
import { TodoItem } from '../todo-item/todo-item';

@ObjectType()
@Relation('todoItem', () => TodoItem, { disableRemove: true })
@Entity({ name: 'sub_task' })
export class SubTask {
  @IDField(() => ID)
  @PrimaryGeneratedColumn()
  id!: number;

  @FilterableField()
  @Column()
  title!: string;

  @FilterableField()
  @Column({ nullable: true })
  description?: string;

  @FilterableField()
  @Column()
  completed!: boolean;

  @FilterableField()
  @Column({ nullable: false, name: 'todo_item_id' })
  todoItemId!: string;

  // do not decorate with @Field
  @ManyToOne(() => TodoItem, (td) => td.subTasks, {
    onDelete: 'CASCADE',
    nullable: false,
  })
  @JoinColumn({ name: 'todo_item_id' })
  todoItem!: TodoItem;

  @FilterableField()
  @CreateDateColumn()
  created!: Date;

  @FilterableField()
  @UpdateDateColumn()
  updated!: Date;
}
```

</TabItem>
<TabItem value="sequelize">

```ts title="sub-task.ts" {18,45-47}
import {
  Table,
  AllowNull,
  Column,
  ForeignKey,
  BelongsTo,
  CreatedAt,
  UpdatedAt,
  Model,
  AutoIncrement,
  PrimaryKey,
} from 'sequelize-typescript';
import { FilterableField, IDField } from '@nestjs-query/query-graphql';
import { ObjectType, ID, GraphQLISODateTime } from '@nestjs/graphql';
import { TodoItem } from '../todo-item/entity/todo-item';

@ObjectType()
@Relation('todoItem', () => TodoItem, { disableRemove: true })
@Table
export class SubTaskEntity extends Model<SubTaskEntity, Partial<SubTaskEntity>> {
  @IDField(() => ID)
  @PrimaryKey
  @AutoIncrement
  @Column
  id!: number;

  @FilterableField()
  @Column
  title!: string;

  @FilterableField({ nullable: true })
  @AllowNull
  @Column
  description?: string;

  @FilterableField()
  @Column
  completed!: boolean;

  @FilterableField()
  @Column
  @ForeignKey(() => TodoItemEntity)
  todoItemId!: number;

  // do not decorate with @Field
  @BelongsTo(() => TodoItem)
  todoItem!: TodoItem;

  @FilterableField(() => GraphQLISODateTime)
  @CreatedAt
  created!: Date;

  @FilterableField(() => GraphQLISODateTime)
  @UpdatedAt
  updated!: Date;
}
```

</TabItem>
</Tabs>

Notice how the `todoItem` is not decorated with a field decorator, instead it is exposed through the `@Relation` decorator.

